<?php

    class itRulesIntelligencerTest extends itTestCase {
        
        /**
         * @test
         */
        public function testScannerSetGet() {
            $i = new itRulesIntelligencer();
            $this->assertNotNull($i->getScanner());
            $s = new itScanner();
            $i->setScanner($s);
            $this->assertEquals($s, $i->getScanner());
        }
        
        /**
         * @test
         */
        public function testRulesSetGet() {
            $i = new itRulesIntelligencer();
            $this->assertNull($i->getRules());
            $r = new itClassRules();
            $this->assertEquals($i, $i->setRules($r));
            $this->assertEquals($r, $i->getRules());
            $this->assertEquals($r, $i->setRulesAndCreate($r));
            $this->assertEquals($r, $i->getRules());
        }
        
        /**
         * @test
         */
        public function testDefaultCacheValues() {
            $i = new itRulesIntelligencer();
            $this->assertType('itLocalCache', $i->getCache());
            $this->assertType('itLocalCache', $i->getFilesCache());
            $this->assertFalse($i->isAggressiveCache());
        }
        
        public function testRulesNotSetException() {
            $i = new itRulesIntelligencer();
            try {
                $i->load('AAA');
                $this->fail();
            } catch(itException $e) {
                $this->assertType('itNullRulesException', $e);
            }
        }
    
        public function testClassRules() {
            $i = new itRulesIntelligencer();
            $i->setRulesAndCreate(new itClassRules())
                ->addClass('Rules_ClassRules_A', TEST_DATA.'/Individual/Intelligencer/Rules/ClassRules/Rules_ClassRules_A.php');
            $this->assertTrue($i->load('Rules_ClassRules_A'));
            $this->assertTrue(class_exists('Rules_ClassRules_A'));
        }
        
        /**
         * no cache for class rules
         */
        public function testNoCacheSimpleRules() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/SimpleRulesNoCache/';
            $bFile = $dir.'Rules_SimpleRulesNoCache_B.php';
            $bClass = 'Rules_SimpleRulesNoCache_B';
            $aFile = $dir.'Rules_SimpleRulesNoCache_A.php';
            $aClass = 'Rules_SimpleRulesNoCache_A';
            itUtil::unlink($bFile);
            $i = new itRulesIntelligencer();
            $i->setCache(null)->setRulesAndCreate(new itSimpleRules())->addFile($aFile)->addFile($bFile);
            $this->assertTrue($i->load($aClass));
            $this->assertTrue(class_exists($aClass));
            $this->assertFalse($i->load($bClass));
            file_put_contents($bFile, "<?php class $bClass {} ?>");
            $this->assertTrue($i->load($bClass));
            $this->assertTrue(class_exists($bClass));
            itUtil::unlink($bFile);
        }
        
        /**
         * no cache for class and simple rules
         */
        public function testNoCacheComplexRules() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/ComplexRulesNoCache/';
            $bFile = $dir.'Rules_ComplexRulesNoCache_B.php';
            $bClass = 'Rules_ComplexRulesNoCache_B';
            $aFile = $dir.'Rules_ComplexRulesNoCache_A.php';
            $aClass = 'Rules_ComplexRulesNoCache_A';
            itUtil::unlink($bFile);
            $i = new itRulesIntelligencer();
            $i->setCache(null)->setFilesCache(null)->setRulesAndCreate(new itComplexRules())
                ->plusFile($aFile)->plusFile($bFile);
            $this->assertTrue($i->load($aClass));
            $this->assertTrue(class_exists($aClass));
            $this->assertFalse($i->load($bClass));
            file_put_contents($bFile, "<?php class $bClass {} ?>");
            $this->assertTrue($i->load($bClass));
            $this->assertTrue(class_exists($bClass));
            itUtil::unlink($bFile);
        }
        
        /**
         * local cache is not aggressive. should be invalidated and reloaded once again
         */
        public function testLocalCacheSimpleRules() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/SimpleRulesLocalCache/';
            $bFile = $dir.'Rules_SimpleRulesLocalCache_B.php';
            $bClass = 'Rules_SimpleRulesLocalCache_B';
            $aFile = $dir.'Rules_SimpleRulesLocalCache_A.php';
            $aClass = 'Rules_SimpleRulesLocalCache_A';
            itUtil::unlink($bFile);
            $i = new itRulesIntelligencer();
            $i->setCache(new itLocalCache())->setRulesAndCreate(new itSimpleRules())->addFile($aFile)->addFile($bFile);
            $this->assertTrue($i->load($aClass));
            $this->assertTrue(class_exists($aClass));
            $this->assertFalse($i->load($bClass));
            file_put_contents($bFile, "<?php class $bClass {} ?>");
            $this->assertTrue($i->load($bClass));
            $this->assertTrue(class_exists($bClass));
            itUtil::unlink($bFile);
        }
        
        /**
         * aggressive local cache. the second class should not be loaded
         */
        public function testLocalCacheAggressiveSimpleRules() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/SimpleRulesLocalCacheAggressive/';
            $bFile = $dir.'Rules_SimpleRulesLocalCacheAggressive_B.php';
            $bClass = 'Rules_SimpleRulesLocalCacheAggressive_B';
            $aFile = $dir.'Rules_SimpleRulesLocalCacheAggressive_A.php';
            $aClass = 'Rules_SimpleRulesLocalCacheAggressive_A';
            itUtil::unlink($bFile);
            $i = new itRulesIntelligencer();
            $i->setCache(new itLocalCache())->setRulesAndCreate(new itSimpleRules())->addFile($aFile)->addFile($bFile);
            $this->assertTrue($i->load($aClass));
            $this->assertTrue(class_exists($aClass));
            $this->assertFalse($i->load($bClass));
            file_put_contents($bFile, "<?php class $bClass {} ?>");
            $this->assertTrue($i->load($bClass));
            $this->assertTrue(class_exists($bClass));
            itUtil::unlink($bFile);
        }
        
        /**
         * local cache is not aggressive. should be invalidated and reloaded once again
         */
        public function testLocalCacheComplexRules() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/ComplexRulesLocalCache/';
            $bFile = $dir.'Rules_ComplexRulesLocalCache_B.php';
            $bClass = 'Rules_ComplexRulesLocalCache_B';
            $aFile = $dir.'Rules_ComplexRulesLocalCache_A.php';
            $aClass = 'Rules_ComplexRulesLocalCache_A';
            itUtil::unlink($bFile);
            $i = new itRulesIntelligencer();
            $i->setCache(new itLocalCache())->setFilesCache(null)->setRulesAndCreate(new itComplexRules())
                ->plusFile($aFile)->plusFile($bFile);
            $this->assertTrue($i->load($aClass));
            $this->assertTrue(class_exists($aClass));
            $this->assertFalse($i->load($bClass));
            file_put_contents($bFile, "<?php class $bClass {} ?>");
            $this->assertTrue($i->load($bClass));
            $this->assertTrue(class_exists($bClass));
            itUtil::unlink($bFile);
        }
        
        /**
         * aggressive local cache. the second class should not be loaded
         */
        public function testLocalCacheAggressiveComplexRules() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/ComplexRulesLocalCacheAggressive/';
            $bFile = $dir.'Rules_ComplexRulesLocalCacheAggressive_B.php';
            $bClass = 'Rules_ComplexRulesLocalCacheAggressive_B';
            $aFile = $dir.'Rules_ComplexRulesLocalCacheAggressive_A.php';
            $aClass = 'Rules_ComplexRulesLocalCacheAggressive_A';
            itUtil::unlink($bFile);
            $i = new itRulesIntelligencer();
            $i->setCache(new itLocalCache())->setFilesCache(null)->setRulesAndCreate(new itComplexRules())
                ->plusFile($aFile)->plusFile($bFile);
            $this->assertTrue($i->load($aClass));
            $this->assertTrue(class_exists($aClass));
            $this->assertFalse($i->load($bClass));
            file_put_contents($bFile, "<?php class $bClass {} ?>");
            $this->assertTrue($i->load($bClass));
            $this->assertTrue(class_exists($bClass));
            itUtil::unlink($bFile);
        }
        
        /**
         * files cache is always aggressive that is why a new file won't be found
         */
        public function testLocalFilesCacheComplexRules() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/ComplexRulesLocalFilesCache/';
            $bFile = $dir.'Rules_ComplexRulesLocalFilesCache_B.php';
            $bClass = 'Rules_ComplexRulesLocalFilesCache_B';
            $aFile = $dir.'Rules_ComplexRulesLocalFilesCache_A.php';
            $aClass = 'Rules_ComplexRulesLocalFilesCache_A';
            itUtil::unlink($bFile);
            $i = new itRulesIntelligencer();
            $i->setCache(null)->setFilesCache(new itLocalCache())->setRulesAndCreate(new itComplexRules())
                ->plusFile($aFile)->plusFile($bFile);
            $this->assertTrue($i->load($aClass));
            $this->assertTrue(class_exists($aClass));
            $this->assertFalse($i->load($bClass));
            file_put_contents($bFile, "<?php class $bClass {} ?>");
            $this->assertFalse($i->load($bClass));
            $this->assertFalse(class_exists($bClass));
            itUtil::unlink($bFile);
        }
   
        public function testPersistentCacheDoesNotExist() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/PersistentCache/';
            $cache = $dir.'cache1.php';
            itUtil::unlink($cache);
            $file = $dir.'Rules_PersistentCache_1.php';
            $class = 'Rules_PersistentCache_1';
            $i = new itRulesIntelligencer('Test');
            $cacheObj = new itPersistentCache($cache);
            $i->setCache($cacheObj)->setRulesAndCreate(new itSimpleRules())
                ->addFile($file);
            $this->assertTrue($i->load($class));
            $this->assertTrue(class_exists($class));
            $this->assertFalse($cacheObj->virgin());
            $this->assertNotNull($cacheObj->get('Test-class'));
            itUtil::unlink($cache);
        }
        
        /**
         * we create manually cache that points to the file X while actual rules do not point to it
         * class should be loaded
         */
        public function testPersistentCacheExists() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/PersistentCache/';
            $file = $dir.'Rules_PersistentCache_2.php';
            $class = 'Rules_PersistentCache_2';
            $cache = $dir.'cache2.php';
            itUtil::unlink($cache);     
            $classRules = new itClassRules();
            $classRules->addClass($class, $file);     
            $cacheObj = new itPersistentCache($cache);
            $cacheObj->set('Test-class', $classRules);
            $i = new itRulesIntelligencer('Test');
            $i->setCache($cacheObj)->setRules(new itSimpleRules());
            $this->assertTrue($i->load($class));
            $this->assertTrue(class_exists($class));
            itUtil::unlink($cache);
        }
        
        public function testPersistentCacheDoesNotContain() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/PersistentCache/';
            $file = $dir.'Rules_PersistentCache_3.php';
            $class = 'Rules_PersistentCache_3';
            $cache = $dir.'cache3.php';
            itUtil::unlink($cache);     
            $classRules = new itClassRules(); 
            $cacheObj = new itPersistentCache($cache);
            $cacheObj->set('Test-class', $classRules);
            $i = new itRulesIntelligencer('Test');
            $i->setCache($cacheObj)->setRulesAndCreate(new itSimpleRules())->addFile($file);
            $this->assertTrue($i->load($class));
            $this->assertTrue(class_exists($class));
            itUtil::unlink($cache);
        }
        
        public function testPersistentAggressiveCacheDoesNotContain() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/PersistentCache/';
            $file = $dir.'Rules_PersistentCache_4.php';
            $class = 'Rules_PersistentCache_4';
            $cache = $dir.'cache4.php';
            itUtil::unlink($cache);     
            $classRules = new itClassRules(); 
            $cacheObj = new itPersistentCache($cache);
            $cacheObj->set('Test-class', $classRules);
            $i = new itRulesIntelligencer('Test');
            $i->setCache($cacheObj)->setAggressiveCache()->setRulesAndCreate(new itSimpleRules())->addFile($file);
            $this->assertFalse($i->load($class));
            $this->assertFalse(class_exists($class));
            itUtil::unlink($cache);
        }
        
        /**
         * the same for complex rules
         * @return unknown_type
         */
        public function testComplexPersistentCacheDoesNotExist() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/ComplexPersistentCache/';
            $cache = $dir.'cache1.php';
            itUtil::unlink($cache);
            $file = $dir.'Rules_ComplexPersistentCache_1.php';
            $class = 'Rules_ComplexPersistentCache_1';
            $i = new itRulesIntelligencer('Test');
            $cacheObj = new itPersistentCache($cache);
            $i->setCache($cacheObj)->setRulesAndCreate(new itComplexRules())
                ->plusFile($file);
            $this->assertTrue($i->load($class));
            $this->assertTrue(class_exists($class));
            $this->assertFalse($cacheObj->virgin());
            $this->assertNotNull($cacheObj->get('Test-class'));
            itUtil::unlink($cache);
        }
        
        /**
         * we create manually cache that points to the file X while actual rules do not point to it
         * class should be loaded
         */
        public function testComplexPersistentCacheExists() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/ComplexPersistentCache/';
            $file = $dir.'Rules_ComplexPersistentCache_2.php';
            $class = 'Rules_ComplexPersistentCache_2';
            $cache = $dir.'cache2.php';
            itUtil::unlink($cache);     
            $classRules = new itClassRules();
            $classRules->addClass($class, $file);     
            $cacheObj = new itPersistentCache($cache);
            $cacheObj->set('Test-class', $classRules);
            $i = new itRulesIntelligencer('Test');
            $i->setCache($cacheObj)->setRules(new itComplexRules());
            $this->assertTrue($i->load($class));
            $this->assertTrue(class_exists($class));
            itUtil::unlink($cache);
        }
        
        public function testComplexPersistentCacheDoesNotContain() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/ComplexPersistentCache/';
            $file = $dir.'Rules_ComplexPersistentCache_3.php';
            $class = 'Rules_ComplexPersistentCache_3';
            $cache = $dir.'cache3.php';
            itUtil::unlink($cache);     
            $classRules = new itClassRules(); 
            $cacheObj = new itPersistentCache($cache);
            $cacheObj->set('Test-class', $classRules);
            $i = new itRulesIntelligencer('Test');
            $i->setCache($cacheObj)->setRulesAndCreate(new itComplexRules())->plusFile($file);
            $this->assertTrue($i->load($class));
            $this->assertTrue(class_exists($class));
            itUtil::unlink($cache);
        }
        
        public function testComplexPersistentAggressiveCacheDoesNotContain() {
            $dir = TEST_DATA.'/Individual/Intelligencer/Rules/ComplexPersistentCache/';
            $file = $dir.'Rules_ComplexPersistentCache_4.php';
            $class = 'Rules_ComplexPersistentCache_4';
            $cache = $dir.'cache4.php';
            itUtil::unlink($cache);     
            $classRules = new itClassRules(); 
            $cacheObj = new itPersistentCache($cache);
            $cacheObj->set('Test-class', $classRules);
            $i = new itRulesIntelligencer('Test');
            $i->setCache($cacheObj)->setAggressiveCache()->setRulesAndCreate(new itComplexRules())->plusFile($file);
            $this->assertFalse($i->load($class));
            $this->assertFalse(class_exists($class));
            itUtil::unlink($cache);
        }
        
    }
?>